import type {
  Ref,
  ShallowRef,
  UnwrapNestedRefs,
} from 'vue'

/**
 * ## 基础类型
 * @description 使用ref包裹
 * @remarks 备注
 * @param {*String}  []
 * @returns {*Object}
 */
//  * TODO: [重要信息] 深层数据响应必须通过triggerRef显示触发
export function useState<T>(initialState: T) {
  const state = ref(initialState) as Ref<T>
  const setState = (value: T): T => {
    state.value = value
    return value
  }
  return [state, setState] as const
}

/**
 * ## 非响应(原生)类型
 */
export function useNativeState<T extends object | any>(
  initialState: T,
) {
  const state = {
    value: initialState,
  }

  const handleArray = (value: T): T => {
    (state.value as unknown[]).length = 0;
    (state.value as unknown[]).push(...(value as any[]))
    return value
  }
  const handleObject = (value: T): T => {
    Object.assign(state as object, value)
    return value
  }
  const factory = (
    v: T = initialState,
  ): ((value: T) => T) => {
    if (
      ['number', 'boolean', 'string'].includes(typeof v)
    ) {
      return (value: T): T => {
        state.value = value
        return value
      }
    }
    else if (v === null || typeof v === 'undefined') {
      return (value: T): T => {
        if (Verify.isArray(value)) {
          handleArray(value)
        }
        else if (Verify.isObject(value)) {
          handleObject(value)
        }
        else {
          state.value = value
        }
        return value
      }
    }
    else if (Verify.isArray(v)) {
      return handleArray
    }
    else {
      return handleObject
    }
  }
  const setState = factory()!

  return [state, setState] as const
}

/**
 * ## 浅层响应
 * @description 使用shallow包裹
 * @remarks 备注
 * TODO: [重要信息] 深层数据响应必须通过triggerRef显示触发
 * [响应变量，设置值，显示触发响应]
 */
export function useShallowState<T>(initialState: T) {
  const state = shallowRef(initialState) as ShallowRef<T>
  const setState = (value: T): T => {
    state.value = value
    return value
  }
  const triggerState = () => triggerRef(state)
  return [state, setState, triggerState] as const
}

/**
 * ## 引用类型
 * @description 使用reactive包裹
 * @remarks 备注
 * @param {*String}  []
 * @returns {*Object}
 * @deprecated 存在问题
 */
export function useQuoteState<T extends object>(
  initialState: T,
) {
  const state = reactive<T>(initialState)
  const handleArray = (value: T): T => {
    (state as UnwrapNestedRefs<unknown>[]).length = 0;
    (state as UnwrapNestedRefs<unknown>[]).push(
      ...(value as unknown[]),
    )
    return value
  }
  const handleObject = (value: T): T => {
    Object.assign(state, value)
    return value
  }
  const setState = (() => {
    if (Verify.isArray(initialState)) {
      return handleArray
    }
    else {
      return handleObject
    }
  })()
  return [state, setState] as const
}
